#include <iostream>
#include <memory>

using std::cout;
using std::endl;
using std::allocator;

//空间适配器的 空间分配与创建对象、空间回收与销毁对象 是分开的
//不同于Point pt(1,2)，分配与创建、回收与销毁 在一起
//对于STL而言，需要同时申请很多个空间，那不如一次申请分配完再创建，
//不要申请一次分配一次

template<typename T>
class Vector
{
public:
    using iterator = T *;

    iterator begin() const
    {
        return _start;
    }

    iterator end() const
    {
        return _finish;
    }

    Vector()
    : _start(nullptr)
    , _finish(nullptr)
    , _end_of_storage(nullptr)
    {
        cout << "Vector()" << endl;
    }

    ~Vector();

    void push_back(const T &value); 
    void pop_back();    

    int size() const;
    int capacity() const;

private:
    void reallocate();//重新分配内存,动态扩容要用的
private:    
    static allocator<T> _alloc;
    //创建空间配置器对象
    //设为静态数据成员，避免占用Vector的capacity

    T * _start;          //指向数组中的第一个元素
    T * _finish;         //指向最后一个实际元素之后的那个元素
    T * _end_of_storage; //指向数组本身之后的位置
};

template <typename T>
allocator<T> Vector<T>::_alloc;

template <typename T>
Vector<T>::~Vector()        //析构函数相当于reallocate简化
{
    cout << "~Vector()" << endl;
    if(_start)
    {
        while(_start != _finish)
        {
            //销毁对象
            _alloc.destroy(--_finish);
        }
        //将空间回收
        _alloc.deallocate(_start, capacity());
    }
}

template <typename T>
void Vector<T>::push_back(const T &value)
{
    /* if(_finish == _end_of_storage) */
    if(size() == capacity())
        //需要扩容
        reallocate();

    //construct：在已经申请出来的空间上构建对象
    _alloc.construct(_finish++, value);
}

template <typename T>
void Vector<T>::pop_back()
{
    if(size() > 0)
    {
        //将空间上的对象销毁
        _alloc.destroy(--_finish);
    }
}

template <typename T>
int Vector<T>::size() const
{
    return _finish - _start;
    //在C++中，指针之间的相减操作实际上得到的是两个指针之间相隔的元素数量，而不是内存地址之间的差值。
    //这是因为在C++中，指针相减的结果会自动除以指向的类型的大小。
}

template <typename T>
int Vector<T>::capacity() const
{
    return _end_of_storage - _start;
}

template <typename T>
void Vector<T>::reallocate()
{
    cout<<"重新分配空间"<<endl;
    //1、计算出旧空间的大小，以及新空间的大小
    int oldCapacity = capacity();
    int newCapacity = oldCapacity > 0 ? 2 * oldCapacity : 1;

    //2、申请新空间
    T *ptmp  = _alloc.allocate(newCapacity);

    if(_start)  //如果旧空间不为空，才执行移动、回收旧空间
    {
        //3、将旧空间上到元素拷贝到新空间来，然后将旧空间上的元素销毁
        std::uninitialized_copy(_start, _finish, ptmp);
        //未初始化的空间的拷贝，需要用未初始化copy
        
/*
        T *start1= _start;
        T *ptmp1=ptmp;
        while(start1 != _finish){
            _alloc.construct(ptmp1, *start1);
            ++ptmp1;
            ++start1;
        }
*/  

        while(_start != _finish)
        {
            //销毁对象
            _alloc.destroy(--_finish);
            //为了配合第4步，所以用--finish
        }
        //4、将旧空间回收
        _alloc.deallocate(_start, oldCapacity);
        //参数是 开头，长度
    }

    //5、三个指针指向新空间
    _start = ptmp;
    _finish = ptmp + oldCapacity;
    _end_of_storage = ptmp + newCapacity;
}

void printCapacity(const Vector<int> &con)
{
    cout << "size() = " << con.size() << endl;
    cout << "capacity() = " << con.capacity() << endl;
}

void printVec(const Vector<int> &con){
    for(auto &elem : con)   //这个遍历方法需要begin、end迭代器
    {
        cout << elem << "  ";
    }
    cout << endl;
}

void test()
{
    Vector<int> vec;
    printCapacity(vec);

    cout << endl;
    vec.push_back(1);
    printCapacity(vec);
    printVec(vec);

    cout << endl;
    vec.push_back(2);
    printCapacity(vec);
    printVec(vec);

    cout << endl;
    vec.push_back(3);
    printCapacity(vec);
    printVec(vec);

    cout << endl;
    vec.push_back(4);
    printCapacity(vec);
    printVec(vec);

    cout << endl;
    vec.push_back(5);
    printCapacity(vec);
    printVec(vec);

    cout << endl;
    vec.push_back(6);
    printCapacity(vec);
    printVec(vec);

    cout << endl;
    vec.push_back(7);
    printCapacity(vec);
    printVec(vec);

    cout << endl;
    vec.push_back(5);
    printCapacity(vec);
    printVec(vec);

    cout << endl;
    vec.push_back(5);
    printCapacity(vec);
    printVec(vec);

    cout << endl;
}

int main()
{
    test();
    return 0;
}


